# @Time    : 2022/8/23 21:39
# @Author  : 南黎
# @FileName: 抠图替换背景.py

import cv2
import  numpy as np

#1.导入本地图片，注意图片的选择，一定要保证在图片缩放处理后，背景图片center点的确定（谨防越界）证件照图片，否则会报错
img=cv2.imread('zjz.png')#要被抠图的证件照
img_back=cv2.imread('back.png')#要替换的背景图片

#2.缩放变换处理图片
# 缩放图片函数cv2.resize解读
# InputArray src ：img_back 输入待改变大小的原图像
# OutputArray dst：None 输出，改变后的图像。这个图像和原图像具有相同的内容，只是大小和原图像不一样而已；
# dsize：输出图像的大小，我这里没有使用这个固定大小的参数，而是启动了下面的比例缩放，你也可以填写具体的缩放大小（500，500）
# fx：width方向的缩放比例
# fy：height方向的缩放比例

#处理背景图片
rows, cols, channels = img_back.shape#获得图片的形状，rows, cols, channels代表行，列像素点数量和通道数
img_back = cv2.resize(img_back, None, fx=0.7, fy=0.7)
cv2.imshow('back', img_back)#展示缩放后的背景图片
#处理证件照图片
rows, cols, channels = img.shape
img = cv2.resize(img, None, fx=0.4, fy=0.4)
cv2.imshow('zjz', img)
rows, cols, channels = img.shape  # rows，cols最后一定要是前景图片的，后面遍历图片需要用到


#3.图片黑白化二值化,获取背景图片区域
# RGB 白色 0，0，0  黑色 255，255，255
# 图片二值化（黑白化）函数cv2.inRange解读
# 取色对照网站推荐 https://www.fontke.com/tool/rgb/6effff/
# 第一个参数：hsv指的是原图
# 第二个参数：lower_red指的是图像中低于这个lower_red的值，图像值变为0
# 第三个参数：upper_red指的是图像中高于这个upper_red的值，图像值变为0
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)#图片颜色模式rgb转换为hsv
# 证件照黑白化mask
lower_blue = np.array([59,29,1])#证件照中低于改值的像素点颜色置为0，如果显示证件照不全，说明这个值要调低
upper_blue = np.array([190, 255, 255])#证件照中高于改值的像素点颜色置为0,如果显示了不该显示的证件照背景杂色，说明这个值要调高
mask = cv2.inRange(hsv, lower_blue, upper_blue)#把范围的像素点颜色变成黑色（人物区域变成黑色），在范围外的像素点颜色变成白色（背景图区域变成白色）
cv2.imshow('mask', mask)#展示黑白化后的证件照

#4.腐蚀膨胀 dilate 消除杂色（但是我这边消除了个寂寞····因为本来背景就有一大块白色····）
#侵蚀了前景物体的边界(始终尝试使前景保持白色)。在二进制图像上执行，简单说是把物体边缘的部分消去杂色
# des = cv2.erode(src, kernel[, anchor[, iterations[, borderType[, borderValue]]]] )
# src 被腐蚀的原始图像
# kernel 代表腐蚀操作时所采用的结构类型。
# anchor 代表element结构中锚点的位置，默认为（-1，-1），在核的中心位置。
# iterations 是腐蚀操作的迭代的次数，默认为1
# borderType 代表边界样式
erode = cv2.erode(mask, None, iterations=1)
cv2.imshow('erode', erode)
dilate = cv2.dilate(erode, None, iterations=1)
cv2.imshow('dilate', dilate)

#5.遍历替换
center = [60,60]  # 自定义固定在新背景图片中的位置，center点的确定（谨防越界）
for i in range(rows):
    for j in range(cols):
        if dilate[i, j] == 0:  # 0代表黑色的点
            img_back[center[0] + i, center[1] + j] = img[i, j]  # 此处替换颜色，为BGR通道
cv2.imshow('result', img_back)#展示替换背景后最终效果的图片

cv2.waitKey(0)#窗口停滞，不加这一行窗口会一闪而逝看不到效果，给imshow提供时间展示图像，所以只有一个空窗口一闪而过。添加了waitkey后，哪怕仅仅是cv2.waitkey(1),我们也能截取到一帧的图像。所以cv2.imshow后边是必须要跟cv2.waitkey的。
cv2.destroyAllWindows()#销毁所有窗口，回收资源